{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "e14f33ea",
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "import pandas as pd\n",
    "from sklearn.model_selection import train_test_split, cross_val_score, StratifiedKFold\n",
    "from sklearn.preprocessing import StandardScaler, LabelEncoder\n",
    "from sklearn.metrics import accuracy_score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "50d41cae",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>电影名称</th>\n",
       "      <th>搞笑镜头</th>\n",
       "      <th>拥抱镜头</th>\n",
       "      <th>打斗镜头</th>\n",
       "      <th>电影类型</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>宝贝当家</td>\n",
       "      <td>45</td>\n",
       "      <td>2</td>\n",
       "      <td>9</td>\n",
       "      <td>喜剧片</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>美人鱼</td>\n",
       "      <td>21</td>\n",
       "      <td>17</td>\n",
       "      <td>5</td>\n",
       "      <td>喜剧片</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>澳门风云3</td>\n",
       "      <td>54</td>\n",
       "      <td>9</td>\n",
       "      <td>11</td>\n",
       "      <td>喜剧片</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>功夫能猫3</td>\n",
       "      <td>39</td>\n",
       "      <td>0</td>\n",
       "      <td>31</td>\n",
       "      <td>喜剧片</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>课影重重</td>\n",
       "      <td>5</td>\n",
       "      <td>2</td>\n",
       "      <td>57</td>\n",
       "      <td>动作片</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>叶间3</td>\n",
       "      <td>3</td>\n",
       "      <td>2</td>\n",
       "      <td>65</td>\n",
       "      <td>动作片</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>伦敦陷落</td>\n",
       "      <td>2</td>\n",
       "      <td>3</td>\n",
       "      <td>55</td>\n",
       "      <td>动作片</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>我的特工爷爷</td>\n",
       "      <td>6</td>\n",
       "      <td>4</td>\n",
       "      <td>21</td>\n",
       "      <td>动作片</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>奔爱</td>\n",
       "      <td>7</td>\n",
       "      <td>46</td>\n",
       "      <td>4</td>\n",
       "      <td>爱情片</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>夜孔雀</td>\n",
       "      <td>9</td>\n",
       "      <td>39</td>\n",
       "      <td>8</td>\n",
       "      <td>爱情片</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>代理情人</td>\n",
       "      <td>9</td>\n",
       "      <td>38</td>\n",
       "      <td>2</td>\n",
       "      <td>爱情片</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>新步步惊心</td>\n",
       "      <td>8</td>\n",
       "      <td>34</td>\n",
       "      <td>17</td>\n",
       "      <td>爱情片</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>唐人街探案</td>\n",
       "      <td>23</td>\n",
       "      <td>3</td>\n",
       "      <td>17</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "      电影名称  搞笑镜头  拥抱镜头  打斗镜头 电影类型\n",
       "0     宝贝当家    45     2     9  喜剧片\n",
       "1      美人鱼    21    17     5  喜剧片\n",
       "2    澳门风云3    54     9    11  喜剧片\n",
       "3    功夫能猫3    39     0    31  喜剧片\n",
       "4     课影重重     5     2    57  动作片\n",
       "5      叶间3     3     2    65  动作片\n",
       "6     伦敦陷落     2     3    55  动作片\n",
       "7   我的特工爷爷     6     4    21  动作片\n",
       "8       奔爱     7    46     4  爱情片\n",
       "9      夜孔雀     9    39     8  爱情片\n",
       "10    代理情人     9    38     2  爱情片\n",
       "11   新步步惊心     8    34    17  爱情片\n",
       "12   唐人街探案    23     3    17  NaN"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data=pd.read_excel(r\"F:\\大三上\\数据分析与数据挖掘\\08\\小课\\电影分类.XLSX\")\n",
    "df = pd.DataFrame(data)\n",
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "ded5166d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 特征和标签\n",
    "X = df[['搞笑镜头', '拥抱镜头', '打斗镜头']]\n",
    "y = df['电影类型']\n",
    "\n",
    "# 将文本标签转换为数字\n",
    "le = LabelEncoder()\n",
    "y = le.fit_transform(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "61fa40ab",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 划分训练集和测试集\n",
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "aec5f87b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 特征缩放\n",
    "scaler = StandardScaler()\n",
    "X_train = scaler.fit_transform(X_train)\n",
    "X_test = scaler.transform(X_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "a7a36aa8",
   "metadata": {
    "collapsed": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "K=5时的交叉验证分数:0.5277777777777778\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\python\\Anaconda\\lib\\site-packages\\sklearn\\model_selection\\_split.py:676: UserWarning: The least populated class in y has only 1 members, which is less than n_splits=3.\n",
      "  warnings.warn(\n",
      "D:\\python\\Anaconda\\lib\\site-packages\\sklearn\\neighbors\\_classification.py:228: FutureWarning: Unlike other reduction functions (e.g. `skew`, `kurtosis`), the default behavior of `mode` typically preserves the axis it acts along. In SciPy 1.11.0, this behavior will change: the default value of `keepdims` will become False, the `axis` over which the statistic is taken will be eliminated, and the value None will no longer be accepted. Set `keepdims` to True or False to avoid this warning.\n",
      "  mode, _ = stats.mode(_y[neigh_ind, k], axis=1)\n",
      "D:\\python\\Anaconda\\lib\\site-packages\\sklearn\\neighbors\\_classification.py:228: FutureWarning: Unlike other reduction functions (e.g. `skew`, `kurtosis`), the default behavior of `mode` typically preserves the axis it acts along. In SciPy 1.11.0, this behavior will change: the default value of `keepdims` will become False, the `axis` over which the statistic is taken will be eliminated, and the value None will no longer be accepted. Set `keepdims` to True or False to avoid this warning.\n",
      "  mode, _ = stats.mode(_y[neigh_ind, k], axis=1)\n",
      "D:\\python\\Anaconda\\lib\\site-packages\\sklearn\\neighbors\\_classification.py:228: FutureWarning: Unlike other reduction functions (e.g. `skew`, `kurtosis`), the default behavior of `mode` typically preserves the axis it acts along. In SciPy 1.11.0, this behavior will change: the default value of `keepdims` will become False, the `axis` over which the statistic is taken will be eliminated, and the value None will no longer be accepted. Set `keepdims` to True or False to avoid this warning.\n",
      "  mode, _ = stats.mode(_y[neigh_ind, k], axis=1)\n",
      "D:\\python\\Anaconda\\lib\\site-packages\\sklearn\\neighbors\\_classification.py:228: FutureWarning: Unlike other reduction functions (e.g. `skew`, `kurtosis`), the default behavior of `mode` typically preserves the axis it acts along. In SciPy 1.11.0, this behavior will change: the default value of `keepdims` will become False, the `axis` over which the statistic is taken will be eliminated, and the value None will no longer be accepted. Set `keepdims` to True or False to avoid this warning.\n",
      "  mode, _ = stats.mode(_y[neigh_ind, k], axis=1)\n"
     ]
    }
   ],
   "source": [
    "\n",
    "# 创建KNN模型\n",
    "knn = KNeighborsClassifier(n_neighbors=5)\n",
    "\n",
    "# 使用交叉验证来选择最佳的K值\n",
    "kf = StratifiedKFold(n_splits=3, shuffle=False)  # 修改交叉验证的折数为3\n",
    "scores = cross_val_score(knn, X_train, y_train, cv=kf)\n",
    "print(f\"K=5时的交叉验证分数:{scores.mean()}\")\n",
    "\n",
    "# 训练模型\n",
    "knn.fit(X_train, y_train)\n",
    "\n",
    "# 预测测试集\n",
    "y_pred = knn.predict(X_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "6c28afd9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "预测准确值为: 1.0\n",
      "预测新电影的类型： '唐人街探案' 是: 喜剧片\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\python\\Anaconda\\lib\\site-packages\\sklearn\\base.py:450: UserWarning: X does not have valid feature names, but StandardScaler was fitted with feature names\n",
      "  warnings.warn(\n",
      "D:\\python\\Anaconda\\lib\\site-packages\\sklearn\\neighbors\\_classification.py:228: FutureWarning: Unlike other reduction functions (e.g. `skew`, `kurtosis`), the default behavior of `mode` typically preserves the axis it acts along. In SciPy 1.11.0, this behavior will change: the default value of `keepdims` will become False, the `axis` over which the statistic is taken will be eliminated, and the value None will no longer be accepted. Set `keepdims` to True or False to avoid this warning.\n",
      "  mode, _ = stats.mode(_y[neigh_ind, k], axis=1)\n"
     ]
    }
   ],
   "source": [
    "# 计算准确率\n",
    "accuracy = accuracy_score(y_test, y_pred)\n",
    "print(f\"预测准确值为: {accuracy}\")\n",
    "\n",
    "# 新电影《唐人街探案》的特征\n",
    "new_movie = [[23, 3, 17]]\n",
    "\n",
    "# 特征缩放\n",
    "new_movie = scaler.transform(new_movie)\n",
    "\n",
    "# 预测新电影的类型\n",
    "predicted_type = le.inverse_transform(knn.predict(new_movie))[0]\n",
    "print(f\"预测新电影的类型： '唐人街探案' 是: {predicted_type}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "65362b8a",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "058d63fa",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.19"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
